package com.quectel.sdk.hikisc;

import com.fasterxml.jackson.core.type.TypeReference;
import com.hikvision.artemis.sdk.constant.SystemHeader;
import com.hikvision.artemis.sdk.util.SignUtil;
import com.quectel.util.common.JacksonUtils;
import com.quectel.util.ex.CheckErrorException;
import com.quectel.util.http.HttpRestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.MalformedURLException;
import java.util.HashMap;
import java.util.Map;
import java.util.TreeMap;
import java.util.UUID;

/**
 * 在这里编写说明
 *
 * @author: rananxin
 * @email: ryan.ran@quectel.com
 * @date: 2022-10-19 11:01:00
 */
public class HikISCRequester {

    private static final Logger logger = LoggerFactory.getLogger(HikISCRequester.class);

    private final String ARTEMIS_PATH = "/artemis";

    private final static String CONTENT_TYPE = "application/json";

    private static final HttpRestUtils HTTP_REST_UTILS = HttpRestUtils.getTrustSSLInstance();

    private String appKey;
    private String appSecret;
    private String host;


    private HikISCRequester(String appKey, String appSecret, String host) {
        this.host = host; // artemis网关服务器ip端口
        this.appKey = appKey;  // 秘钥appkey
        this.appSecret = appSecret;// 秘钥appSecret
    }


    public static HikISCRequester getInstance(String appKey, String appSecret, String host) {

        return new HikISCRequester(appKey, appSecret, host);
    }

    public String post(String path, Object params) {
        if (this.host == null) {
            throw new CheckErrorException("checked host " + this.host + " is not accessible");
        }
        final String previewURLsApi = ARTEMIS_PATH + path;
        Map<String, String> queryMap = new HashMap<String, String>(2);
        queryMap.put("https://", previewURLsApi);
        String body = null;
        if (params != null) {
            body = params instanceof String ? params.toString() : JacksonUtils.toJsonString(params);
        }
        return MyHikUtils.getInstace(appKey, appSecret, host).doPostStringArtemis(queryMap, body);
    }


    /*流一定要关闭
     if (httpResponse instanceof Closeable) {
         *      *                 try {
         *      *                     ((Closeable)httpResponse).close();
         *      *                 } catch (IOException e) {
         *      *                     e.printStackTrace();
         *      *                 }
         *      *             }
     */
    public CloseableHttpResponse postBackHttpResponse(String path, Object params) {
        if (this.host == null) {
            throw new CheckErrorException("checked host " + this.host + " is not accessible");
        }
        final String previewURLsApi = ARTEMIS_PATH + path;
        Map<String, String> queryMap = new HashMap<String, String>(2);
        queryMap.put("https://", previewURLsApi);
        String body = null;
        if (params != null) {
            body = params instanceof String ? params.toString() : JacksonUtils.toJsonString(params);
        }
        return MyHikUtils.getInstace(appKey, appSecret, host).doPostStringImgArtemis(queryMap, body);
    }


    private static final class MyHikUtils {
        private static final Logger logger = LoggerFactory.getLogger(MyHikUtils.class);

        //自定义参与签名Header前缀（可选,默认只有"X-Ca-"开头的参与到Header签名）
        //private final static List<String> CUSTOM_HEADERS_TO_SIGN_PREFIX = new ArrayList<String>();

        //调用网关成功的标志,标志位
        private final static String SUCC_PRE = "2";

        //调用网关重定向的标志,标志位
        private final static String REDIRECT_PRE = "3";

        private String appKey;
        private String appSecret;
        private String host;


        private MyHikUtils(String appKey, String appSecret, String host) {
            this.appKey = appKey;
            this.appSecret = appSecret;
            this.host = host;
        }

        public static MyHikUtils getInstace(String appKey, String appSecret, String host) {
            return new MyHikUtils(appKey, appSecret, host);
        }


        /**
         * postString请求
         *
         * @param path artemis配置的get请求的路径 是一个数组长度为1的Hashmap集合，只存一组数据，key为http的请求方式，value为host后面的path路径。
         * @param body postString String请求体
         * @return POST json类型接口  返回字符串类型
         */


        public String doPostStringArtemis(Map<String, String> path, String body) {
            /**
             * 根据传入的path获取是请求是http还是https
             */
            String httpSchema = (String) path.keySet().toArray()[0];

            if (httpSchema == null || StringUtils.isEmpty(httpSchema)) {
                throw new CheckErrorException("httpSchema错误" + "httpSchema: " + httpSchema);
            }
            try {
                Map<String, String> headers = new TreeMap<>();
                headers.put("Accept", "*/*");
                headers.put("Content-Type", CONTENT_TYPE);

                headers = sign("POST", path.get(httpSchema), headers, appKey, appSecret);

                Pair<Integer, String> result = HTTP_REST_UTILS.post(httpSchema + this.host + path.get(httpSchema), body, headers, new TypeReference<String>() {
                });

                if (String.valueOf(result.getLeft()).startsWith(SUCC_PRE) || String.valueOf(result.getLeft()).startsWith(REDIRECT_PRE)) {//调用Artemis网关成功
                    logger.info("the Artemis Request is Success,statusCode:" + result.getLeft());
                    //调用服务端
                    return result.getRight();
                }

            } catch (Exception e) {
                logger.error("the Artemis PostString Request is failed[doPostStringArtemis]", e);
            }
            return null;
        }


        /**
         * postString请求
         * * 这个流一定记得关闭 否则内存泄露
         * * if (httpResponse instanceof Closeable) {
         * *                 try {
         * *                     ((Closeable)httpResponse).close();
         * *                 } catch (IOException e) {
         * *                     e.printStackTrace();
         * *                 }
         * *             }
         *
         * @param path artemis配置的get请求的路径 是一个数组长度为1的Hashmap集合，只存一组数据，key为http的请求方式，value为host后面的path路径。
         * @param body postString String请求体
         * @return POST json请求类型图片下载接口  HttpResponse类型
         */
        public CloseableHttpResponse doPostStringImgArtemis(Map<String, String> path, String body) {

            /**
             * 根据传入的path获取是请求是http还是https
             */
            String httpSchema = (String) path.keySet().toArray()[0];

            if (httpSchema == null || StringUtils.isEmpty(httpSchema)) {
                throw new CheckErrorException("httpSchema错误" + "httpSchema: " + httpSchema);
            }
            try {
                Map<String, String> headers = new TreeMap<>();
                headers.put("Accept", "*/*");
                headers.put("Content-Type", CONTENT_TYPE);

                headers = sign("POST", path.get(httpSchema), headers, appKey, appSecret);


                return HTTP_REST_UTILS.postBackHttpResponse(httpSchema + this.host + path.get(httpSchema), body, headers);

            } catch (Exception e) {
                logger.error("the Artemis PostString Request is failed[doPostStringArtemis]", e);
            }
            return null;
        }


        /**
         * 鍒濆鍖栧熀纭�Header
         *
         * @param method
         * @param path
         * @param headers
         * @param appKey
         * @param appSecret
         * @return
         * @throws MalformedURLException
         */
        private static Map<String, String> sign(String method, String path,
                                                Map<String, String> headers,
                                                String appKey, String appSecret)
                throws MalformedURLException {
            if (headers == null) {
                headers = new HashMap<String, String>();
            }

            headers.put(SystemHeader.X_CA_TIMESTAMP, String.valueOf(System.currentTimeMillis()));
            headers.put(SystemHeader.X_CA_NONCE, UUID.randomUUID().toString());
            headers.put(SystemHeader.X_CA_KEY, appKey);
            headers.put(SystemHeader.X_CA_SIGNATURE,
                    SignUtil.sign(appSecret, method, path, headers, null, null, null));

            return headers;
        }
    }

    public static void main(String[] args) throws Exception {
        String s = "POST\n" +
                "*/*\n" +
                "text/plain;charset=UTF-8\n" +
                "header-a:A\n" +
                "header-b:b\n" +
                "x-ca-key:29666671\n" +
                "x-ca-timestamp:1479968678000\n" +
                "/artemis/api/example?a-body=a&qa=a&qb=B&x-body=x";
    }

}
